Refactor operators into an enum

(This commit is not formatted properly)

Relates to #46
This commit is contained in:
Sebastian Schmidt 2019-04-14 16:54:35 +02:00
parent 697fbb5d45
commit 6c078c49e5
10 changed files with 589 additions and 962 deletions

View File

@ -18,18 +18,22 @@ impl fmt::Display for EvalexprError {
), ),
ExpectedString { actual } => { ExpectedString { actual } => {
write!(f, "Expected a Value::String, but got {:?}.", actual) write!(f, "Expected a Value::String, but got {:?}.", actual)
}, }
ExpectedInt { actual } => write!(f, "Expected a Value::Int, but got {:?}.", actual), ExpectedInt { actual } => write!(f, "Expected a Value::Int, but got {:?}.", actual),
ExpectedFloat { actual } => write!(f, "Expected a Value::Float, but got {:?}.", actual), ExpectedFloat { actual } => write!(f, "Expected a Value::Float, but got {:?}.", actual),
ExpectedNumber { actual } => { ExpectedNumber { actual } => write!(
write!(f, "Expected a Value::Float or Value::Int, but got {:?}.", actual) f,
}, "Expected a Value::Float or Value::Int, but got {:?}.",
ExpectedNumberOrString { actual } => { actual
write!(f, "Expected a Value::Number or a Value::String, but got {:?}.", actual) ),
}, ExpectedNumberOrString { actual } => write!(
f,
"Expected a Value::Number or a Value::String, but got {:?}.",
actual
),
ExpectedBoolean { actual } => { ExpectedBoolean { actual } => {
write!(f, "Expected a Value::Boolean, but got {:?}.", actual) write!(f, "Expected a Value::Boolean, but got {:?}.", actual)
}, }
ExpectedTuple { actual } => write!(f, "Expected a Value::Tuple, but got {:?}.", actual), ExpectedTuple { actual } => write!(f, "Expected a Value::Tuple, but got {:?}.", actual),
ExpectedEmpty { actual } => write!(f, "Expected a Value::Empty, but got {:?}.", actual), ExpectedEmpty { actual } => write!(f, "Expected a Value::Empty, but got {:?}.", actual),
AppendedToLeafNode => write!(f, "Tried to append a node to a leaf node."), AppendedToLeafNode => write!(f, "Tried to append a node to a leaf node."),
@ -49,7 +53,7 @@ impl fmt::Display for EvalexprError {
), ),
TypeError { expected, actual } => { TypeError { expected, actual } => {
write!(f, "Expected one of {:?}, but got {:?}.", expected, actual) write!(f, "Expected one of {:?}, but got {:?}.", expected, actual)
}, }
UnmatchedLBrace => write!(f, "Found an unmatched opening parenthesis '('."), UnmatchedLBrace => write!(f, "Found an unmatched opening parenthesis '('."),
UnmatchedRBrace => write!(f, "Found an unmatched closing parenthesis ')'."), UnmatchedRBrace => write!(f, "Found an unmatched closing parenthesis ')'."),
UnmatchedPartialToken { first, second } => { UnmatchedPartialToken { first, second } => {
@ -67,7 +71,7 @@ impl fmt::Display for EvalexprError {
first first
) )
} }
}, }
AdditionError { augend, addend } => write!(f, "Error adding {} + {}", augend, addend), AdditionError { augend, addend } => write!(f, "Error adding {} + {}", augend, addend),
SubtractionError { SubtractionError {
minuend, minuend,
@ -80,11 +84,15 @@ impl fmt::Display for EvalexprError {
} => write!(f, "Error multiplying {} * {}", multiplicand, multiplier), } => write!(f, "Error multiplying {} * {}", multiplicand, multiplier),
DivisionError { dividend, divisor } => { DivisionError { dividend, divisor } => {
write!(f, "Error dividing {} / {}", dividend, divisor) write!(f, "Error dividing {} / {}", dividend, divisor)
}, }
ModulationError { dividend, divisor } => { ModulationError { dividend, divisor } => {
write!(f, "Error modulating {} % {}", dividend, divisor) write!(f, "Error modulating {} % {}", dividend, divisor)
}, }
InvalidRegex { regex, message } => write!(f, "Regular expression {:?} is invalid: {:?}", regex, message), InvalidRegex { regex, message } => write!(
f,
"Regular expression {:?} is invalid: {:?}",
regex, message
),
ContextNotManipulable => write!(f, "Cannot manipulate context"), ContextNotManipulable => write!(f, "Cannot manipulate context"),
IllegalEscapeSequence(string) => write!(f, "Illegal escape sequence: {}", string), IllegalEscapeSequence(string) => write!(f, "Illegal escape sequence: {}", string),
CustomMessage(message) => write!(f, "Error: {}", message), CustomMessage(message) => write!(f, "Error: {}", message),

View File

@ -290,7 +290,7 @@ impl EvalexprError {
/// Constructs `EvalexprError::InvalidRegex(regex)` /// Constructs `EvalexprError::InvalidRegex(regex)`
pub fn invalid_regex(regex: String, message: String) -> Self { pub fn invalid_regex(regex: String, message: String) -> Self {
EvalexprError::InvalidRegex{ regex, message } EvalexprError::InvalidRegex { regex, message }
} }
} }
@ -309,10 +309,7 @@ pub(crate) fn expect_operator_argument_amount(
} }
/// Returns `Ok(())` if the actual and expected parameters are equal, and `Err(Error::WrongFunctionArgumentAmount)` otherwise. /// Returns `Ok(())` if the actual and expected parameters are equal, and `Err(Error::WrongFunctionArgumentAmount)` otherwise.
pub fn expect_function_argument_amount( pub fn expect_function_argument_amount(actual: usize, expected: usize) -> EvalexprResult<()> {
actual: usize,
expected: usize,
) -> EvalexprResult<()> {
if actual == expected { if actual == expected {
Ok(()) Ok(())
} else { } else {

View File

@ -67,7 +67,6 @@ 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), Some(2),
@ -76,7 +75,10 @@ pub fn builtin_function(identifier: &str) -> Option<Function> {
let re_str = expect_string(&arguments[1])?; let re_str = expect_string(&arguments[1])?;
match Regex::new(re_str) { match Regex::new(re_str) {
Ok(re) => Ok(Value::Boolean(re.is_match(subject))), Ok(re) => Ok(Value::Boolean(re.is_match(subject))),
Err(err) => Err(EvalexprError::invalid_regex(re_str.to_string(), format!("{}", err))) Err(err) => Err(EvalexprError::invalid_regex(
re_str.to_string(),
format!("{}", err),
)),
} }
}), }),
)), )),
@ -89,7 +91,10 @@ pub fn builtin_function(identifier: &str) -> Option<Function> {
let repl = expect_string(&arguments[2])?; let repl = expect_string(&arguments[2])?;
match Regex::new(re_str) { match Regex::new(re_str) {
Ok(re) => Ok(Value::String(re.replace_all(subject, repl).to_string())), Ok(re) => Ok(Value::String(re.replace_all(subject, repl).to_string())),
Err(err) => Err(EvalexprError::invalid_regex(re_str.to_string(), format!("{}", err))), Err(err) => Err(EvalexprError::invalid_regex(
re_str.to_string(),
format!("{}", err),
)),
} }
}), }),
)), )),

View File

@ -2,140 +2,37 @@ use std::fmt::{Display, Error, Formatter};
use operator::*; use operator::*;
impl Display for RootNode { impl Display for Operator {
fn fmt(&self, _f: &mut Formatter) -> Result<(), Error> {
Ok(())
}
}
impl Display for Add {
fn fmt(&self, f: &mut Formatter) -> Result<(), Error> { fn fmt(&self, f: &mut Formatter) -> Result<(), Error> {
write!(f, "+") use crate::operator::Operator::*;
} match self {
} RootNode => Ok(()),
Add => write!(f, "+"),
Sub => write!(f, "-"),
Neg => write!(f, "-"),
Mul => write!(f, "*"),
Div => write!(f, "/"),
Mod => write!(f, "%"),
Exp => write!(f, "^"),
impl Display for Sub { Eq => write!(f, "=="),
fn fmt(&self, f: &mut Formatter) -> Result<(), Error> { Neq => write!(f, "!="),
write!(f, "-") Gt => write!(f, ">"),
} Lt => write!(f, "<"),
} Geq => write!(f, ">="),
Leq => write!(f, "<="),
And => write!(f, "&&"),
Or => write!(f, "||"),
Not => write!(f, "!"),
impl Display for Neg { Tuple => write!(f, ", "),
fn fmt(&self, f: &mut Formatter) -> Result<(), Error> { Assign => write!(f, " = "),
write!(f, "-")
}
}
impl Display for Mul { Chain => write!(f, "; "),
fn fmt(&self, f: &mut Formatter) -> Result<(), Error> {
write!(f, "*")
}
}
impl Display for Div { Const { value } => write!(f, "{}", value),
fn fmt(&self, f: &mut Formatter) -> Result<(), Error> { VariableIdentifier { identifier } => write!(f, "{}", identifier),
write!(f, "/") FunctionIdentifier { identifier } => write!(f, "{}", identifier),
} }
}
impl Display for Mod {
fn fmt(&self, f: &mut Formatter) -> Result<(), Error> {
write!(f, "%")
}
}
impl Display for Exp {
fn fmt(&self, f: &mut Formatter) -> Result<(), Error> {
write!(f, "^")
}
}
impl Display for Eq {
fn fmt(&self, f: &mut Formatter) -> Result<(), Error> {
write!(f, "==")
}
}
impl Display for Neq {
fn fmt(&self, f: &mut Formatter) -> Result<(), Error> {
write!(f, "!=")
}
}
impl Display for Gt {
fn fmt(&self, f: &mut Formatter) -> Result<(), Error> {
write!(f, ">")
}
}
impl Display for Lt {
fn fmt(&self, f: &mut Formatter) -> Result<(), Error> {
write!(f, "<")
}
}
impl Display for Geq {
fn fmt(&self, f: &mut Formatter) -> Result<(), Error> {
write!(f, ">=")
}
}
impl Display for Leq {
fn fmt(&self, f: &mut Formatter) -> Result<(), Error> {
write!(f, "<=")
}
}
impl Display for And {
fn fmt(&self, f: &mut Formatter) -> Result<(), Error> {
write!(f, "&&")
}
}
impl Display for Or {
fn fmt(&self, f: &mut Formatter) -> Result<(), Error> {
write!(f, "||")
}
}
impl Display for Not {
fn fmt(&self, f: &mut Formatter) -> Result<(), Error> {
write!(f, "!")
}
}
impl Display for Tuple {
fn fmt(&self, f: &mut Formatter) -> Result<(), Error> {
write!(f, ", ")
}
}
impl Display for Assign {
fn fmt(&self, f: &mut Formatter) -> Result<(), Error> {
write!(f, "; ")
}
}
impl Display for Chain {
fn fmt(&self, f: &mut Formatter) -> Result<(), Error> {
write!(f, " = ")
}
}
impl Display for Const {
fn fmt(&self, f: &mut Formatter) -> Result<(), Error> {
write!(f, "{}", self.value)
}
}
impl Display for VariableIdentifier {
fn fmt(&self, f: &mut Formatter) -> Result<(), Error> {
write!(f, "{}", self.identifier)
}
}
impl Display for FunctionIdentifier {
fn fmt(&self, f: &mut Formatter) -> Result<(), Error> {
write!(f, "{}", self.identifier)
} }
} }

View File

@ -1,165 +1,128 @@
use std::fmt::{Debug, Display};
use function::builtin::builtin_function; use function::builtin::builtin_function;
use crate::{context::Context, error::*, value::Value}; use crate::{context::Context, error::*, value::Value};
mod display; mod display;
pub trait Operator: Debug + Display { #[derive(Debug)]
pub enum Operator {
RootNode,
Add,
Sub,
Neg,
Mul,
Div,
Mod,
Exp,
Eq,
Neq,
Gt,
Lt,
Geq,
Leq,
And,
Or,
Not,
Tuple,
Assign,
Chain,
Const { value: Value },
VariableIdentifier { identifier: String },
FunctionIdentifier { identifier: String },
}
impl Operator {
pub(crate) fn value(value: Value) -> Self {
Operator::Const { value }
}
pub(crate) fn variable_identifier(identifier: String) -> Self {
Operator::VariableIdentifier { identifier }
}
pub(crate) fn function_identifier(identifier: String) -> Self {
Operator::FunctionIdentifier { identifier }
}
/// Returns the precedence of the operator. /// Returns the precedence of the operator.
/// A high precedence means that the operator has priority to be deeper in the tree. /// A high precedence means that the operator has priority to be deeper in the tree.
// Make this a const fn once #57563 is resolved // Make this a const fn once #57563 is resolved
fn precedence(&self) -> i32; pub(crate) fn precedence(&self) -> i32 {
use crate::operator::Operator::*;
match self {
RootNode => 200,
Add | Sub => 95,
Neg => 110,
Mul | Div | Mod => 100,
Exp => 120,
Eq | Neq | Gt | Lt | Geq | Leq => 80,
And => 75,
Or => 70,
Not => 110,
Tuple => 40,
Assign => 50,
Chain => 0,
Const { value: _ } => 200,
VariableIdentifier { identifier: _ } => 200,
FunctionIdentifier { identifier: _ } => 190,
}
}
/// Returns true if chains of operators with the same precedence as this one should be evaluated left-to-right, /// Returns true if chains of operators with the same precedence as this one should be evaluated left-to-right,
/// and false if they should be evaluated right-to-left. /// and false if they should be evaluated right-to-left.
/// Left-to-right chaining has priority if operators with different order but same precedence are chained. /// Left-to-right chaining has priority if operators with different order but same precedence are chained.
// Make this a const fn once #57563 is resolved // Make this a const fn once #57563 is resolved
fn is_left_to_right(&self) -> bool { pub(crate) fn is_left_to_right(&self) -> bool {
true use crate::operator::Operator::*;
match self {
Assign => false,
FunctionIdentifier { identifier: _ } => false,
_ => true,
}
} }
/// 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
fn is_leaf(&self) -> bool { pub(crate) fn is_leaf(&self) -> bool {
self.max_argument_amount() == 0 self.max_argument_amount() == 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
fn max_argument_amount(&self) -> usize; pub(crate) fn max_argument_amount(&self) -> usize {
use crate::operator::Operator::*;
match self {
Add | Sub | Mul | Div | Mod | Exp | Eq | Neq | Gt | Lt | Geq | Leq | And | Or
| Tuple | Assign | Chain => 2,
Not | Neg | RootNode => 1,
Const { value: _ } => 0,
VariableIdentifier { identifier: _ } => 0,
FunctionIdentifier { identifier: _ } => 1,
}
}
/// Evaluates the operator with the given arguments and context. /// Evaluates the operator with the given arguments and context.
fn eval(&self, arguments: &[Value], context: &dyn Context) -> EvalexprResult<Value>; pub(crate) fn eval(&self, arguments: &[Value], context: &dyn Context) -> EvalexprResult<Value> {
use crate::operator::Operator::*;
/// Evaluates the operator with the given arguments and mutable context. match self {
fn eval_mut(&self, arguments: &[Value], context: &mut dyn Context) -> EvalexprResult<Value> { RootNode => {
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
}
/// 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)]
pub struct RootNode;
#[derive(Debug)]
pub struct Add;
#[derive(Debug)]
pub struct Sub;
#[derive(Debug)]
pub struct Neg;
#[derive(Debug)]
pub struct Mul;
#[derive(Debug)]
pub struct Div;
#[derive(Debug)]
pub struct Mod;
#[derive(Debug)]
pub struct Exp;
#[derive(Debug)]
pub struct Eq;
#[derive(Debug)]
pub struct Neq;
#[derive(Debug)]
pub struct Gt;
#[derive(Debug)]
pub struct Lt;
#[derive(Debug)]
pub struct Geq;
#[derive(Debug)]
pub struct Leq;
#[derive(Debug)]
pub struct And;
#[derive(Debug)]
pub struct Or;
#[derive(Debug)]
pub struct Not;
#[derive(Debug)]
pub struct Tuple;
#[derive(Debug)]
pub struct Assign;
#[derive(Debug)]
pub struct Chain;
#[derive(Debug)]
pub struct Const {
value: Value,
}
impl Const {
pub fn new(value: Value) -> Self {
Self { value }
}
}
#[derive(Debug)]
pub struct VariableIdentifier {
identifier: String,
}
impl VariableIdentifier {
pub fn new(identifier: String) -> Self {
Self { identifier }
}
}
#[derive(Debug)]
pub struct FunctionIdentifier {
identifier: String,
}
impl FunctionIdentifier {
pub fn new(identifier: String) -> Self {
Self { identifier }
}
}
impl Operator for RootNode {
fn precedence(&self) -> i32 {
200
}
fn max_argument_amount(&self) -> usize {
1
}
fn eval(&self, arguments: &[Value], _context: &Context) -> EvalexprResult<Value> {
if let Some(first) = arguments.first() { if let Some(first) = arguments.first() {
Ok(first.clone()) Ok(first.clone())
} else { } else {
Ok(Value::Empty) Ok(Value::Empty)
} }
} }
} Add => {
impl Operator for Add {
fn precedence(&self) -> i32 {
95
}
fn max_argument_amount(&self) -> usize {
2
}
fn eval(&self, arguments: &[Value], _context: &Context) -> EvalexprResult<Value> {
expect_operator_argument_amount(arguments.len(), 2)?; expect_operator_argument_amount(arguments.len(), 2)?;
expect_number_or_string(&arguments[0])?; expect_number_or_string(&arguments[0])?;
expect_number_or_string(&arguments[1])?; expect_number_or_string(&arguments[1])?;
@ -185,18 +148,7 @@ impl Operator for Add {
)) ))
} }
} }
} Sub => {
impl Operator for Sub {
fn precedence(&self) -> i32 {
95
}
fn max_argument_amount(&self) -> usize {
2
}
fn eval(&self, arguments: &[Value], _context: &Context) -> EvalexprResult<Value> {
expect_operator_argument_amount(arguments.len(), 2)?; expect_operator_argument_amount(arguments.len(), 2)?;
expect_number(&arguments[0])?; expect_number(&arguments[0])?;
expect_number(&arguments[1])?; expect_number(&arguments[1])?;
@ -217,18 +169,7 @@ impl Operator for Sub {
)) ))
} }
} }
} Neg => {
impl Operator for Neg {
fn precedence(&self) -> i32 {
110
}
fn max_argument_amount(&self) -> usize {
1
}
fn eval(&self, arguments: &[Value], _context: &Context) -> EvalexprResult<Value> {
expect_operator_argument_amount(arguments.len(), 1)?; expect_operator_argument_amount(arguments.len(), 1)?;
expect_number(&arguments[0])?; expect_number(&arguments[0])?;
@ -243,18 +184,7 @@ impl Operator for Neg {
Ok(Value::Float(-arguments[0].as_number().unwrap())) Ok(Value::Float(-arguments[0].as_number().unwrap()))
} }
} }
} Mul => {
impl Operator for Mul {
fn precedence(&self) -> i32 {
100
}
fn max_argument_amount(&self) -> usize {
2
}
fn eval(&self, arguments: &[Value], _context: &Context) -> EvalexprResult<Value> {
expect_operator_argument_amount(arguments.len(), 2)?; expect_operator_argument_amount(arguments.len(), 2)?;
expect_number(&arguments[0])?; expect_number(&arguments[0])?;
expect_number(&arguments[1])?; expect_number(&arguments[1])?;
@ -275,18 +205,7 @@ impl Operator for Mul {
)) ))
} }
} }
} Div => {
impl Operator for Div {
fn precedence(&self) -> i32 {
100
}
fn max_argument_amount(&self) -> usize {
2
}
fn eval(&self, arguments: &[Value], _context: &Context) -> EvalexprResult<Value> {
expect_operator_argument_amount(arguments.len(), 2)?; expect_operator_argument_amount(arguments.len(), 2)?;
expect_number(&arguments[0])?; expect_number(&arguments[0])?;
expect_number(&arguments[1])?; expect_number(&arguments[1])?;
@ -307,18 +226,7 @@ impl Operator for Div {
)) ))
} }
} }
} Mod => {
impl Operator for Mod {
fn precedence(&self) -> i32 {
100
}
fn max_argument_amount(&self) -> usize {
2
}
fn eval(&self, arguments: &[Value], _context: &Context) -> EvalexprResult<Value> {
expect_operator_argument_amount(arguments.len(), 2)?; expect_operator_argument_amount(arguments.len(), 2)?;
expect_number(&arguments[0])?; expect_number(&arguments[0])?;
expect_number(&arguments[1])?; expect_number(&arguments[1])?;
@ -339,18 +247,7 @@ impl Operator for Mod {
)) ))
} }
} }
} Exp => {
impl Operator for Exp {
fn precedence(&self) -> i32 {
120
}
fn max_argument_amount(&self) -> usize {
2
}
fn eval(&self, arguments: &[Value], _context: &Context) -> EvalexprResult<Value> {
expect_operator_argument_amount(arguments.len(), 2)?; expect_operator_argument_amount(arguments.len(), 2)?;
expect_number(&arguments[0])?; expect_number(&arguments[0])?;
expect_number(&arguments[1])?; expect_number(&arguments[1])?;
@ -362,18 +259,7 @@ impl Operator for Exp {
.powf(arguments[1].as_number().unwrap()), .powf(arguments[1].as_number().unwrap()),
)) ))
} }
} Eq => {
impl Operator for Eq {
fn precedence(&self) -> i32 {
80
}
fn max_argument_amount(&self) -> usize {
2
}
fn eval(&self, arguments: &[Value], _context: &Context) -> EvalexprResult<Value> {
expect_operator_argument_amount(arguments.len(), 2)?; expect_operator_argument_amount(arguments.len(), 2)?;
if arguments[0] == arguments[1] { if arguments[0] == arguments[1] {
@ -382,18 +268,7 @@ impl Operator for Eq {
Ok(Value::Boolean(false)) Ok(Value::Boolean(false))
} }
} }
} Neq => {
impl Operator for Neq {
fn precedence(&self) -> i32 {
80
}
fn max_argument_amount(&self) -> usize {
2
}
fn eval(&self, arguments: &[Value], _context: &Context) -> EvalexprResult<Value> {
expect_operator_argument_amount(arguments.len(), 2)?; expect_operator_argument_amount(arguments.len(), 2)?;
if arguments[0] != arguments[1] { if arguments[0] != arguments[1] {
@ -402,18 +277,7 @@ impl Operator for Neq {
Ok(Value::Boolean(false)) Ok(Value::Boolean(false))
} }
} }
} Gt => {
impl Operator for Gt {
fn precedence(&self) -> i32 {
80
}
fn max_argument_amount(&self) -> usize {
2
}
fn eval(&self, arguments: &[Value], _context: &Context) -> EvalexprResult<Value> {
expect_operator_argument_amount(arguments.len(), 2)?; expect_operator_argument_amount(arguments.len(), 2)?;
expect_number_or_string(&arguments[0])?; expect_number_or_string(&arguments[0])?;
expect_number_or_string(&arguments[1])?; expect_number_or_string(&arguments[1])?;
@ -438,18 +302,7 @@ impl Operator for Gt {
} }
} }
} }
} Lt => {
impl Operator for Lt {
fn precedence(&self) -> i32 {
80
}
fn max_argument_amount(&self) -> usize {
2
}
fn eval(&self, arguments: &[Value], _context: &Context) -> EvalexprResult<Value> {
expect_operator_argument_amount(arguments.len(), 2)?; expect_operator_argument_amount(arguments.len(), 2)?;
expect_number_or_string(&arguments[0])?; expect_number_or_string(&arguments[0])?;
expect_number_or_string(&arguments[1])?; expect_number_or_string(&arguments[1])?;
@ -474,18 +327,7 @@ impl Operator for Lt {
} }
} }
} }
} Geq => {
impl Operator for Geq {
fn precedence(&self) -> i32 {
80
}
fn max_argument_amount(&self) -> usize {
2
}
fn eval(&self, arguments: &[Value], _context: &Context) -> EvalexprResult<Value> {
expect_operator_argument_amount(arguments.len(), 2)?; expect_operator_argument_amount(arguments.len(), 2)?;
expect_number_or_string(&arguments[0])?; expect_number_or_string(&arguments[0])?;
expect_number_or_string(&arguments[1])?; expect_number_or_string(&arguments[1])?;
@ -510,18 +352,7 @@ impl Operator for Geq {
} }
} }
} }
} Leq => {
impl Operator for Leq {
fn precedence(&self) -> i32 {
80
}
fn max_argument_amount(&self) -> usize {
2
}
fn eval(&self, arguments: &[Value], _context: &Context) -> EvalexprResult<Value> {
expect_operator_argument_amount(arguments.len(), 2)?; expect_operator_argument_amount(arguments.len(), 2)?;
expect_number_or_string(&arguments[0])?; expect_number_or_string(&arguments[0])?;
expect_number_or_string(&arguments[1])?; expect_number_or_string(&arguments[1])?;
@ -546,18 +377,7 @@ impl Operator for Leq {
} }
} }
} }
} And => {
impl Operator for And {
fn precedence(&self) -> i32 {
75
}
fn max_argument_amount(&self) -> usize {
2
}
fn eval(&self, arguments: &[Value], _context: &Context) -> EvalexprResult<Value> {
expect_operator_argument_amount(arguments.len(), 2)?; expect_operator_argument_amount(arguments.len(), 2)?;
let a = expect_boolean(&arguments[0])?; let a = expect_boolean(&arguments[0])?;
let b = expect_boolean(&arguments[1])?; let b = expect_boolean(&arguments[1])?;
@ -568,18 +388,7 @@ impl Operator for And {
Ok(Value::Boolean(false)) Ok(Value::Boolean(false))
} }
} }
} Or => {
impl Operator for Or {
fn precedence(&self) -> i32 {
70
}
fn max_argument_amount(&self) -> usize {
2
}
fn eval(&self, arguments: &[Value], _context: &Context) -> EvalexprResult<Value> {
expect_operator_argument_amount(arguments.len(), 2)?; expect_operator_argument_amount(arguments.len(), 2)?;
let a = expect_boolean(&arguments[0])?; let a = expect_boolean(&arguments[0])?;
let b = expect_boolean(&arguments[1])?; let b = expect_boolean(&arguments[1])?;
@ -590,18 +399,7 @@ impl Operator for Or {
Ok(Value::Boolean(false)) Ok(Value::Boolean(false))
} }
} }
} Not => {
impl Operator for Not {
fn precedence(&self) -> i32 {
110
}
fn max_argument_amount(&self) -> usize {
1
}
fn eval(&self, arguments: &[Value], _context: &Context) -> EvalexprResult<Value> {
expect_operator_argument_amount(arguments.len(), 1)?; expect_operator_argument_amount(arguments.len(), 1)?;
let a = expect_boolean(&arguments[0])?; let a = expect_boolean(&arguments[0])?;
@ -611,18 +409,7 @@ impl Operator for Not {
Ok(Value::Boolean(false)) Ok(Value::Boolean(false))
} }
} }
} Tuple => {
impl Operator for Tuple {
fn precedence(&self) -> i32 {
40
}
fn max_argument_amount(&self) -> usize {
2
}
fn eval(&self, arguments: &[Value], _context: &Context) -> EvalexprResult<Value> {
expect_operator_argument_amount(arguments.len(), 2)?; expect_operator_argument_amount(arguments.len(), 2)?;
if let Value::Tuple(tuple) = &arguments[0] { if let Value::Tuple(tuple) = &arguments[0] {
let mut tuple = tuple.clone(); let mut tuple = tuple.clone();
@ -645,110 +432,29 @@ impl Operator for Tuple {
} }
} }
} }
} Assign => Err(EvalexprError::ContextNotManipulable),
Chain => {
impl Operator for Assign {
fn precedence(&self) -> i32 {
50
}
fn is_left_to_right(&self) -> bool {
false
}
fn max_argument_amount(&self) -> usize {
2
}
fn eval(&self, _arguments: &[Value], _context: &Context) -> EvalexprResult<Value> {
Err(EvalexprError::ContextNotManipulable)
}
fn eval_mut(&self, arguments: &[Value], context: &mut Context) -> EvalexprResult<Value> {
expect_operator_argument_amount(arguments.len(), 2)?;
let target = expect_string(&arguments[0])?;
context.set_value(target.into(), arguments[1].clone())?;
Ok(Value::Empty)
}
}
impl Operator for Chain {
fn precedence(&self) -> i32 {
0
}
fn max_argument_amount(&self) -> usize {
2
}
fn eval(&self, arguments: &[Value], _context: &Context) -> Result<Value, EvalexprError> {
if arguments.is_empty() { if arguments.is_empty() {
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.get(1).cloned().unwrap_or(Value::Empty))
} }
} Const { value } => {
impl Operator for Const {
fn precedence(&self) -> i32 {
200
}
fn max_argument_amount(&self) -> usize {
0
}
fn eval(&self, arguments: &[Value], _context: &Context) -> EvalexprResult<Value> {
expect_operator_argument_amount(arguments.len(), 0)?; expect_operator_argument_amount(arguments.len(), 0)?;
Ok(self.value.clone()) Ok(value.clone())
} }
} VariableIdentifier { identifier } => {
if let Some(value) = context.get_value(&identifier).cloned() {
impl Operator for VariableIdentifier {
fn precedence(&self) -> i32 {
200
}
fn max_argument_amount(&self) -> usize {
0
}
fn eval(&self, _arguments: &[Value], context: &Context) -> EvalexprResult<Value> {
if let Some(value) = context.get_value(&self.identifier).cloned() {
Ok(value) Ok(value)
} else { } else {
Err(EvalexprError::VariableIdentifierNotFound( Err(EvalexprError::VariableIdentifierNotFound(
self.identifier.clone(), identifier.clone(),
)) ))
} }
} }
FunctionIdentifier { identifier } => {
fn identifier(&self) -> Option<&str> {
Some(&self.identifier)
}
fn variable_identifier(&self) -> Option<&str> {
Some(&self.identifier)
}
}
impl Operator for FunctionIdentifier {
fn precedence(&self) -> i32 {
190
}
fn is_left_to_right(&self) -> bool {
false
}
fn max_argument_amount(&self) -> usize {
1
}
fn eval(&self, arguments: &[Value], context: &Context) -> EvalexprResult<Value> {
expect_operator_argument_amount(arguments.len(), 1)?; expect_operator_argument_amount(arguments.len(), 1)?;
let arguments = if let Value::Tuple(arguments) = &arguments[0] { let arguments = if let Value::Tuple(arguments) = &arguments[0] {
@ -757,22 +463,35 @@ impl Operator for FunctionIdentifier {
arguments arguments
}; };
if let Some(function) = context.get_function(&self.identifier) { if let Some(function) = context.get_function(&identifier) {
function.call(arguments) function.call(arguments)
} else if let Some(builtin_function) = builtin_function(&self.identifier) { } else if let Some(builtin_function) = builtin_function(&identifier) {
builtin_function.call(arguments) builtin_function.call(arguments)
} else { } else {
Err(EvalexprError::FunctionIdentifierNotFound( Err(EvalexprError::FunctionIdentifierNotFound(
self.identifier.clone(), identifier.clone(),
)) ))
} }
} }
}
fn identifier(&self) -> Option<&str> {
Some(&self.identifier)
} }
fn function_identifier(&self) -> Option<&str> { /// Evaluates the operator with the given arguments and mutable context.
Some(&self.identifier) pub(crate) fn eval_mut(
&self,
arguments: &[Value],
context: &mut dyn Context,
) -> EvalexprResult<Value> {
use crate::operator::Operator::*;
match self {
Assign => {
expect_operator_argument_amount(arguments.len(), 2)?;
let target = expect_string(&arguments[0])?;
context.set_value(target.into(), arguments[1].clone())?;
Ok(Value::Empty)
}
_ => self.eval(arguments, context),
}
} }
} }

View File

@ -83,7 +83,7 @@ fn char_to_partial_token(c: char) -> PartialToken {
} else { } else {
PartialToken::Literal(c.to_string()) PartialToken::Literal(c.to_string())
} }
}, }
} }
} }
@ -233,7 +233,7 @@ fn partial_tokens_to_tokens(mut tokens: &[PartialToken]) -> EvalexprResult<Vec<T
PartialToken::Token(token) => { PartialToken::Token(token) => {
cutoff = 1; cutoff = 1;
Some(token) Some(token)
}, }
PartialToken::Literal(literal) => { PartialToken::Literal(literal) => {
cutoff = 1; cutoff = 1;
if let Ok(number) = literal.parse::<IntType>() { if let Ok(number) = literal.parse::<IntType>() {
@ -245,38 +245,38 @@ fn partial_tokens_to_tokens(mut tokens: &[PartialToken]) -> EvalexprResult<Vec<T
} else { } else {
Some(Token::Identifier(literal.to_string())) Some(Token::Identifier(literal.to_string()))
} }
}, }
PartialToken::Whitespace => { PartialToken::Whitespace => {
cutoff = 1; cutoff = 1;
None None
}, }
PartialToken::Eq => match second { PartialToken::Eq => match second {
Some(PartialToken::Eq) => Some(Token::Eq), Some(PartialToken::Eq) => Some(Token::Eq),
_ => { _ => {
cutoff = 1; cutoff = 1;
Some(Token::Assign) Some(Token::Assign)
}, }
}, },
PartialToken::ExclamationMark => match second { PartialToken::ExclamationMark => match second {
Some(PartialToken::Eq) => Some(Token::Eq), Some(PartialToken::Eq) => Some(Token::Eq),
_ => { _ => {
cutoff = 1; cutoff = 1;
Some(Token::Not) Some(Token::Not)
}, }
}, },
PartialToken::Gt => match second { PartialToken::Gt => match second {
Some(PartialToken::Eq) => Some(Token::Geq), Some(PartialToken::Eq) => Some(Token::Geq),
_ => { _ => {
cutoff = 1; cutoff = 1;
Some(Token::Gt) Some(Token::Gt)
}, }
}, },
PartialToken::Lt => match second { PartialToken::Lt => match second {
Some(PartialToken::Eq) => Some(Token::Leq), Some(PartialToken::Eq) => Some(Token::Leq),
_ => { _ => {
cutoff = 1; cutoff = 1;
Some(Token::Lt) Some(Token::Lt)
}, }
}, },
PartialToken::Ampersand => match second { PartialToken::Ampersand => match second {
Some(PartialToken::Ampersand) => Some(Token::And), Some(PartialToken::Ampersand) => Some(Token::And),

View File

@ -1,5 +1,5 @@
use Node;
use std::slice::Iter; use std::slice::Iter;
use Node;
/// An iterator that traverses an operator tree in pre-order. /// An iterator that traverses an operator tree in pre-order.
pub struct NodeIter<'a> { pub struct NodeIter<'a> {
@ -47,7 +47,7 @@ impl<'a> Iterator for NodeIter<'a> {
impl Node { impl Node {
/// Returns an iterator over all nodes in this tree. /// Returns an iterator over all nodes in this tree.
pub fn iter(&self) -> impl Iterator<Item=&Node> { pub fn iter(&self) -> impl Iterator<Item = &Node> {
NodeIter::new(self) NodeIter::new(self)
} }
} }

View File

@ -35,19 +35,19 @@ mod iter;
#[derive(Debug)] #[derive(Debug)]
pub struct Node { pub struct Node {
children: Vec<Node>, children: Vec<Node>,
operator: Box<dyn Operator>, operator: Operator,
} }
impl Node { impl Node {
fn new<T: Operator + 'static>(operator: T) -> Self { fn new(operator: Operator) -> Self {
Self { Self {
children: Vec::new(), children: Vec::new(),
operator: Box::new(operator), operator,
} }
} }
fn root_node() -> Self { fn root_node() -> Self {
Self::new(RootNode) Self::new(Operator::RootNode)
} }
/// Returns an iterator over all identifiers in this expression. /// Returns an iterator over all identifiers in this expression.
@ -67,7 +67,11 @@ impl Node {
/// assert_eq!(iter.next(), None); /// assert_eq!(iter.next(), None);
/// ``` /// ```
pub fn iter_identifiers(&self) -> impl Iterator<Item = &str> { pub fn iter_identifiers(&self) -> impl Iterator<Item = &str> {
self.iter().filter_map(|node| node.operator.identifier()) self.iter().filter_map(|node| match node.operator() {
Operator::VariableIdentifier { identifier }
| Operator::FunctionIdentifier { identifier } => Some(identifier.as_str()),
_ => None,
})
} }
/// Returns an iterator over all variable identifiers in this expression. /// Returns an iterator over all variable identifiers in this expression.
@ -86,7 +90,10 @@ impl Node {
/// assert_eq!(iter.next(), None); /// assert_eq!(iter.next(), None);
/// ``` /// ```
pub fn iter_variable_identifiers(&self) -> impl Iterator<Item = &str> { pub fn iter_variable_identifiers(&self) -> impl Iterator<Item = &str> {
self.iter().filter_map(|node| node.operator.variable_identifier()) self.iter().filter_map(|node| match node.operator() {
Operator::VariableIdentifier { identifier } => Some(identifier.as_str()),
_ => None,
})
} }
/// Returns an iterator over all function identifiers in this expression. /// Returns an iterator over all function identifiers in this expression.
@ -103,7 +110,10 @@ impl Node {
/// assert_eq!(iter.next(), None); /// assert_eq!(iter.next(), None);
/// ``` /// ```
pub fn iter_function_identifiers(&self) -> impl Iterator<Item = &str> { pub fn iter_function_identifiers(&self) -> impl Iterator<Item = &str> {
self.iter().filter_map(|node| node.operator.function_identifier()) self.iter().filter_map(|node| match node.operator() {
Operator::FunctionIdentifier { identifier } => Some(identifier.as_str()),
_ => None,
})
} }
/// Evaluates the operator tree rooted at this node with the given context. /// Evaluates the operator tree rooted at this node with the given context.
@ -347,7 +357,7 @@ impl Node {
&self.children &self.children
} }
fn operator(&self) -> &Box<dyn Operator> { fn operator(&self) -> &Operator {
&self.operator &self.operator
} }
@ -404,60 +414,60 @@ pub(crate) fn tokens_to_operator_tree(tokens: Vec<Token>) -> EvalexprResult<Node
let next = token_iter.peek().cloned(); let next = token_iter.peek().cloned();
let node = match token.clone() { let node = match token.clone() {
Token::Plus => Some(Node::new(Add)), Token::Plus => Some(Node::new(Operator::Add)),
Token::Minus => { Token::Minus => {
if last_token_is_rightsided_value { if last_token_is_rightsided_value {
Some(Node::new(Sub)) Some(Node::new(Operator::Sub))
} else { } else {
Some(Node::new(Neg)) Some(Node::new(Operator::Neg))
} }
}, }
Token::Star => Some(Node::new(Mul)), Token::Star => Some(Node::new(Operator::Mul)),
Token::Slash => Some(Node::new(Div)), Token::Slash => Some(Node::new(Operator::Div)),
Token::Percent => Some(Node::new(Mod)), Token::Percent => Some(Node::new(Operator::Mod)),
Token::Hat => Some(Node::new(Exp)), Token::Hat => Some(Node::new(Operator::Exp)),
Token::Eq => Some(Node::new(Eq)), Token::Eq => Some(Node::new(Operator::Eq)),
Token::Neq => Some(Node::new(Neq)), Token::Neq => Some(Node::new(Operator::Neq)),
Token::Gt => Some(Node::new(Gt)), Token::Gt => Some(Node::new(Operator::Gt)),
Token::Lt => Some(Node::new(Lt)), Token::Lt => Some(Node::new(Operator::Lt)),
Token::Geq => Some(Node::new(Geq)), Token::Geq => Some(Node::new(Operator::Geq)),
Token::Leq => Some(Node::new(Leq)), Token::Leq => Some(Node::new(Operator::Leq)),
Token::And => Some(Node::new(And)), Token::And => Some(Node::new(Operator::And)),
Token::Or => Some(Node::new(Or)), Token::Or => Some(Node::new(Operator::Or)),
Token::Not => Some(Node::new(Not)), Token::Not => Some(Node::new(Operator::Not)),
Token::LBrace => { Token::LBrace => {
root.push(Node::root_node()); root.push(Node::root_node());
None None
}, }
Token::RBrace => { Token::RBrace => {
if root.len() < 2 { if root.len() < 2 {
return Err(EvalexprError::UnmatchedRBrace); return Err(EvalexprError::UnmatchedRBrace);
} else { } else {
root.pop() root.pop()
} }
}, }
Token::Comma => Some(Node::new(Tuple)), Token::Comma => Some(Node::new(Operator::Tuple)),
Token::Assign => Some(Node::new(Assign)), Token::Assign => Some(Node::new(Operator::Assign)),
Token::Semicolon => Some(Node::new(Chain)), Token::Semicolon => Some(Node::new(Operator::Chain)),
Token::Identifier(identifier) => { Token::Identifier(identifier) => {
let mut result = Some(Node::new(VariableIdentifier::new(identifier.clone()))); let mut result = Some(Node::new(Operator::variable_identifier(identifier.clone())));
if let Some(next) = next { if let Some(next) = next {
if next == &Token::Assign { if next == &Token::Assign {
result = Some(Node::new(Const::new(identifier.clone().into()))); result = Some(Node::new(Operator::value(identifier.clone().into())));
} else if next.is_leftsided_value() { } else if next.is_leftsided_value() {
result = Some(Node::new(FunctionIdentifier::new(identifier))); result = Some(Node::new(Operator::function_identifier(identifier)));
} }
} }
result result
}, }
Token::Float(float) => Some(Node::new(Const::new(Value::Float(float)))), Token::Float(float) => Some(Node::new(Operator::value(Value::Float(float)))),
Token::Int(int) => Some(Node::new(Const::new(Value::Int(int)))), Token::Int(int) => Some(Node::new(Operator::value(Value::Int(int)))),
Token::Boolean(boolean) => Some(Node::new(Const::new(Value::Boolean(boolean)))), Token::Boolean(boolean) => Some(Node::new(Operator::value(Value::Boolean(boolean)))),
Token::String(string) => Some(Node::new(Const::new(Value::String(string)))), Token::String(string) => Some(Node::new(Operator::value(Value::String(string)))),
}; };
if let Some(node) = node { if let Some(node) = node {

View File

@ -21,7 +21,7 @@ impl Display for Value {
value.fmt(f)?; value.fmt(f)?;
} }
write!(f, ")") write!(f, ")")
}, }
Value::Empty => write!(f, "()"), Value::Empty => write!(f, "()"),
} }
} }

View File

@ -279,18 +279,9 @@ fn test_n_ary_functions() {
#[test] #[test]
fn test_builtin_functions() { fn test_builtin_functions() {
assert_eq!( assert_eq!(eval("min(4.0, 3)"), Ok(Value::Int(3)));
eval("min(4.0, 3)"), assert_eq!(eval("max(4.0, 3)"), Ok(Value::Float(4.0)));
Ok(Value::Int(3)) assert_eq!(eval("len(\"foobar\")"), Ok(Value::Int(6)));
);
assert_eq!(
eval("max(4.0, 3)"),
Ok(Value::Float(4.0))
);
assert_eq!(
eval("len(\"foobar\")"),
Ok(Value::Int(6))
);
assert_eq!( assert_eq!(
eval("str::to_lowercase(\"FOOBAR\")"), eval("str::to_lowercase(\"FOOBAR\")"),
Ok(Value::from("foobar")) Ok(Value::from("foobar"))
@ -317,10 +308,10 @@ fn test_regex_functions() {
Ok(Value::Boolean(false)) Ok(Value::Boolean(false))
); );
match eval("str::regex_matches(\"foo\", \"[\")") { match eval("str::regex_matches(\"foo\", \"[\")") {
Err(EvalexprError::InvalidRegex{ regex, message }) => { Err(EvalexprError::InvalidRegex { regex, message }) => {
assert_eq!(regex, "["); assert_eq!(regex, "[");
assert!(message.contains("unclosed character class")); assert!(message.contains("unclosed character class"));
}, }
v => panic!(v), v => panic!(v),
}; };
assert_eq!( assert_eq!(