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 } => {
write!(f, "Expected a Value::String, 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),
ExpectedNumber { actual } => {
write!(f, "Expected a Value::Float or Value::Int, but got {:?}.", actual)
},
ExpectedNumberOrString { actual } => {
write!(f, "Expected a Value::Number or a Value::String, but got {:?}.", actual)
},
ExpectedNumber { actual } => write!(
f,
"Expected a Value::Float or Value::Int, but got {:?}.",
actual
),
ExpectedNumberOrString { actual } => write!(
f,
"Expected a Value::Number or a Value::String, but got {:?}.",
actual
),
ExpectedBoolean { actual } => {
write!(f, "Expected a Value::Boolean, 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),
AppendedToLeafNode => write!(f, "Tried to append a node to a leaf node."),
@ -49,7 +53,7 @@ impl fmt::Display for EvalexprError {
),
TypeError { expected, actual } => {
write!(f, "Expected one of {:?}, but got {:?}.", expected, actual)
},
}
UnmatchedLBrace => write!(f, "Found an unmatched opening parenthesis '('."),
UnmatchedRBrace => write!(f, "Found an unmatched closing parenthesis ')'."),
UnmatchedPartialToken { first, second } => {
@ -67,7 +71,7 @@ impl fmt::Display for EvalexprError {
first
)
}
},
}
AdditionError { augend, addend } => write!(f, "Error adding {} + {}", augend, addend),
SubtractionError {
minuend,
@ -80,11 +84,15 @@ impl fmt::Display for EvalexprError {
} => write!(f, "Error multiplying {} * {}", multiplicand, multiplier),
DivisionError { dividend, divisor } => {
write!(f, "Error dividing {} / {}", dividend, divisor)
},
}
ModulationError { 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"),
IllegalEscapeSequence(string) => write!(f, "Illegal escape sequence: {}", string),
CustomMessage(message) => write!(f, "Error: {}", message),

View File

@ -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.
pub fn expect_function_argument_amount(
actual: usize,
expected: usize,
) -> EvalexprResult<()> {
pub fn expect_function_argument_amount(actual: usize, expected: usize) -> EvalexprResult<()> {
if actual == expected {
Ok(())
} else {

View File

@ -67,7 +67,6 @@ pub fn builtin_function(identifier: &str) -> Option<Function> {
)),
// string functions
#[cfg(feature = "regex_support")]
"str::regex_matches" => Some(Function::new(
Some(2),
@ -76,7 +75,10 @@ pub fn builtin_function(identifier: &str) -> Option<Function> {
let re_str = expect_string(&arguments[1])?;
match Regex::new(re_str) {
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])?;
match Regex::new(re_str) {
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::*;
impl Display for RootNode {
fn fmt(&self, _f: &mut Formatter) -> Result<(), Error> {
Ok(())
}
}
impl Display for Add {
impl Display for Operator {
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 {
fn fmt(&self, f: &mut Formatter) -> Result<(), Error> {
write!(f, "-")
}
}
Eq => write!(f, "=="),
Neq => 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 {
fn fmt(&self, f: &mut Formatter) -> Result<(), Error> {
write!(f, "-")
}
}
Tuple => write!(f, ", "),
Assign => write!(f, " = "),
impl Display for Mul {
fn fmt(&self, f: &mut Formatter) -> Result<(), Error> {
write!(f, "*")
}
}
Chain => write!(f, "; "),
impl Display for Div {
fn fmt(&self, f: &mut Formatter) -> Result<(), Error> {
write!(f, "/")
Const { value } => write!(f, "{}", value),
VariableIdentifier { identifier } => write!(f, "{}", identifier),
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 crate::{context::Context, error::*, value::Value};
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.
/// A high precedence means that the operator has priority to be deeper in the tree.
// 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,
/// 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.
// Make this a const fn once #57563 is resolved
fn is_left_to_right(&self) -> bool {
true
pub(crate) fn is_left_to_right(&self) -> bool {
use crate::operator::Operator::*;
match self {
Assign => false,
FunctionIdentifier { identifier: _ } => false,
_ => true,
}
}
/// True if this operator is a leaf, meaning it accepts no arguments.
// 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
}
/// Returns the maximum amount of arguments required by this operator.
// 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.
fn eval(&self, arguments: &[Value], context: &dyn Context) -> EvalexprResult<Value>;
/// Evaluates the operator with the given arguments and mutable context.
fn eval_mut(&self, arguments: &[Value], context: &mut dyn Context) -> EvalexprResult<Value> {
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> {
pub(crate) fn eval(&self, arguments: &[Value], context: &dyn Context) -> EvalexprResult<Value> {
use crate::operator::Operator::*;
match self {
RootNode => {
if let Some(first) = arguments.first() {
Ok(first.clone())
} else {
Ok(Value::Empty)
}
}
}
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> {
Add => {
expect_operator_argument_amount(arguments.len(), 2)?;
expect_number_or_string(&arguments[0])?;
expect_number_or_string(&arguments[1])?;
@ -185,18 +148,7 @@ impl Operator for Add {
))
}
}
}
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> {
Sub => {
expect_operator_argument_amount(arguments.len(), 2)?;
expect_number(&arguments[0])?;
expect_number(&arguments[1])?;
@ -217,18 +169,7 @@ impl Operator for Sub {
))
}
}
}
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> {
Neg => {
expect_operator_argument_amount(arguments.len(), 1)?;
expect_number(&arguments[0])?;
@ -243,18 +184,7 @@ impl Operator for Neg {
Ok(Value::Float(-arguments[0].as_number().unwrap()))
}
}
}
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> {
Mul => {
expect_operator_argument_amount(arguments.len(), 2)?;
expect_number(&arguments[0])?;
expect_number(&arguments[1])?;
@ -275,18 +205,7 @@ impl Operator for Mul {
))
}
}
}
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> {
Div => {
expect_operator_argument_amount(arguments.len(), 2)?;
expect_number(&arguments[0])?;
expect_number(&arguments[1])?;
@ -307,18 +226,7 @@ impl Operator for Div {
))
}
}
}
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> {
Mod => {
expect_operator_argument_amount(arguments.len(), 2)?;
expect_number(&arguments[0])?;
expect_number(&arguments[1])?;
@ -339,18 +247,7 @@ impl Operator for Mod {
))
}
}
}
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> {
Exp => {
expect_operator_argument_amount(arguments.len(), 2)?;
expect_number(&arguments[0])?;
expect_number(&arguments[1])?;
@ -362,18 +259,7 @@ impl Operator for Exp {
.powf(arguments[1].as_number().unwrap()),
))
}
}
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> {
Eq => {
expect_operator_argument_amount(arguments.len(), 2)?;
if arguments[0] == arguments[1] {
@ -382,18 +268,7 @@ impl Operator for Eq {
Ok(Value::Boolean(false))
}
}
}
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> {
Neq => {
expect_operator_argument_amount(arguments.len(), 2)?;
if arguments[0] != arguments[1] {
@ -402,18 +277,7 @@ impl Operator for Neq {
Ok(Value::Boolean(false))
}
}
}
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> {
Gt => {
expect_operator_argument_amount(arguments.len(), 2)?;
expect_number_or_string(&arguments[0])?;
expect_number_or_string(&arguments[1])?;
@ -438,18 +302,7 @@ impl Operator for Gt {
}
}
}
}
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> {
Lt => {
expect_operator_argument_amount(arguments.len(), 2)?;
expect_number_or_string(&arguments[0])?;
expect_number_or_string(&arguments[1])?;
@ -474,18 +327,7 @@ impl Operator for Lt {
}
}
}
}
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> {
Geq => {
expect_operator_argument_amount(arguments.len(), 2)?;
expect_number_or_string(&arguments[0])?;
expect_number_or_string(&arguments[1])?;
@ -510,18 +352,7 @@ impl Operator for Geq {
}
}
}
}
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> {
Leq => {
expect_operator_argument_amount(arguments.len(), 2)?;
expect_number_or_string(&arguments[0])?;
expect_number_or_string(&arguments[1])?;
@ -546,18 +377,7 @@ impl Operator for Leq {
}
}
}
}
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> {
And => {
expect_operator_argument_amount(arguments.len(), 2)?;
let a = expect_boolean(&arguments[0])?;
let b = expect_boolean(&arguments[1])?;
@ -568,18 +388,7 @@ impl Operator for And {
Ok(Value::Boolean(false))
}
}
}
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> {
Or => {
expect_operator_argument_amount(arguments.len(), 2)?;
let a = expect_boolean(&arguments[0])?;
let b = expect_boolean(&arguments[1])?;
@ -590,18 +399,7 @@ impl Operator for Or {
Ok(Value::Boolean(false))
}
}
}
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> {
Not => {
expect_operator_argument_amount(arguments.len(), 1)?;
let a = expect_boolean(&arguments[0])?;
@ -611,18 +409,7 @@ impl Operator for Not {
Ok(Value::Boolean(false))
}
}
}
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> {
Tuple => {
expect_operator_argument_amount(arguments.len(), 2)?;
if let Value::Tuple(tuple) = &arguments[0] {
let mut tuple = tuple.clone();
@ -645,110 +432,29 @@ impl Operator for Tuple {
}
}
}
}
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> {
Assign => Err(EvalexprError::ContextNotManipulable),
Chain => {
if arguments.is_empty() {
return Err(EvalexprError::wrong_operator_argument_amount(0, 1));
}
Ok(arguments.get(1).cloned().unwrap_or(Value::Empty))
}
}
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> {
Const { value } => {
expect_operator_argument_amount(arguments.len(), 0)?;
Ok(self.value.clone())
Ok(value.clone())
}
}
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() {
VariableIdentifier { identifier } => {
if let Some(value) = context.get_value(&identifier).cloned() {
Ok(value)
} else {
Err(EvalexprError::VariableIdentifierNotFound(
self.identifier.clone(),
identifier.clone(),
))
}
}
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> {
FunctionIdentifier { identifier } => {
expect_operator_argument_amount(arguments.len(), 1)?;
let arguments = if let Value::Tuple(arguments) = &arguments[0] {
@ -757,22 +463,35 @@ impl Operator for FunctionIdentifier {
arguments
};
if let Some(function) = context.get_function(&self.identifier) {
if let Some(function) = context.get_function(&identifier) {
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)
} else {
Err(EvalexprError::FunctionIdentifierNotFound(
self.identifier.clone(),
identifier.clone(),
))
}
}
fn identifier(&self) -> Option<&str> {
Some(&self.identifier)
}
}
fn function_identifier(&self) -> Option<&str> {
Some(&self.identifier)
/// Evaluates the operator with the given arguments and mutable context.
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 {
PartialToken::Literal(c.to_string())
}
},
}
}
}
@ -233,7 +233,7 @@ fn partial_tokens_to_tokens(mut tokens: &[PartialToken]) -> EvalexprResult<Vec<T
PartialToken::Token(token) => {
cutoff = 1;
Some(token)
},
}
PartialToken::Literal(literal) => {
cutoff = 1;
if let Ok(number) = literal.parse::<IntType>() {
@ -245,38 +245,38 @@ fn partial_tokens_to_tokens(mut tokens: &[PartialToken]) -> EvalexprResult<Vec<T
} else {
Some(Token::Identifier(literal.to_string()))
}
},
}
PartialToken::Whitespace => {
cutoff = 1;
None
},
}
PartialToken::Eq => match second {
Some(PartialToken::Eq) => Some(Token::Eq),
_ => {
cutoff = 1;
Some(Token::Assign)
},
}
},
PartialToken::ExclamationMark => match second {
Some(PartialToken::Eq) => Some(Token::Eq),
_ => {
cutoff = 1;
Some(Token::Not)
},
}
},
PartialToken::Gt => match second {
Some(PartialToken::Eq) => Some(Token::Geq),
_ => {
cutoff = 1;
Some(Token::Gt)
},
}
},
PartialToken::Lt => match second {
Some(PartialToken::Eq) => Some(Token::Leq),
_ => {
cutoff = 1;
Some(Token::Lt)
},
}
},
PartialToken::Ampersand => match second {
Some(PartialToken::Ampersand) => Some(Token::And),

View File

@ -1,5 +1,5 @@
use Node;
use std::slice::Iter;
use Node;
/// An iterator that traverses an operator tree in pre-order.
pub struct NodeIter<'a> {

View File

@ -35,19 +35,19 @@ mod iter;
#[derive(Debug)]
pub struct Node {
children: Vec<Node>,
operator: Box<dyn Operator>,
operator: Operator,
}
impl Node {
fn new<T: Operator + 'static>(operator: T) -> Self {
fn new(operator: Operator) -> Self {
Self {
children: Vec::new(),
operator: Box::new(operator),
operator,
}
}
fn root_node() -> Self {
Self::new(RootNode)
Self::new(Operator::RootNode)
}
/// Returns an iterator over all identifiers in this expression.
@ -67,7 +67,11 @@ impl Node {
/// assert_eq!(iter.next(), None);
/// ```
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.
@ -86,7 +90,10 @@ impl Node {
/// assert_eq!(iter.next(), None);
/// ```
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.
@ -103,7 +110,10 @@ impl Node {
/// assert_eq!(iter.next(), None);
/// ```
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.
@ -347,7 +357,7 @@ impl Node {
&self.children
}
fn operator(&self) -> &Box<dyn Operator> {
fn 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 node = match token.clone() {
Token::Plus => Some(Node::new(Add)),
Token::Plus => Some(Node::new(Operator::Add)),
Token::Minus => {
if last_token_is_rightsided_value {
Some(Node::new(Sub))
Some(Node::new(Operator::Sub))
} else {
Some(Node::new(Neg))
Some(Node::new(Operator::Neg))
}
},
Token::Star => Some(Node::new(Mul)),
Token::Slash => Some(Node::new(Div)),
Token::Percent => Some(Node::new(Mod)),
Token::Hat => Some(Node::new(Exp)),
}
Token::Star => Some(Node::new(Operator::Mul)),
Token::Slash => Some(Node::new(Operator::Div)),
Token::Percent => Some(Node::new(Operator::Mod)),
Token::Hat => Some(Node::new(Operator::Exp)),
Token::Eq => Some(Node::new(Eq)),
Token::Neq => Some(Node::new(Neq)),
Token::Gt => Some(Node::new(Gt)),
Token::Lt => Some(Node::new(Lt)),
Token::Geq => Some(Node::new(Geq)),
Token::Leq => Some(Node::new(Leq)),
Token::And => Some(Node::new(And)),
Token::Or => Some(Node::new(Or)),
Token::Not => Some(Node::new(Not)),
Token::Eq => Some(Node::new(Operator::Eq)),
Token::Neq => Some(Node::new(Operator::Neq)),
Token::Gt => Some(Node::new(Operator::Gt)),
Token::Lt => Some(Node::new(Operator::Lt)),
Token::Geq => Some(Node::new(Operator::Geq)),
Token::Leq => Some(Node::new(Operator::Leq)),
Token::And => Some(Node::new(Operator::And)),
Token::Or => Some(Node::new(Operator::Or)),
Token::Not => Some(Node::new(Operator::Not)),
Token::LBrace => {
root.push(Node::root_node());
None
},
}
Token::RBrace => {
if root.len() < 2 {
return Err(EvalexprError::UnmatchedRBrace);
} else {
root.pop()
}
},
}
Token::Comma => Some(Node::new(Tuple)),
Token::Assign => Some(Node::new(Assign)),
Token::Semicolon => Some(Node::new(Chain)),
Token::Comma => Some(Node::new(Operator::Tuple)),
Token::Assign => Some(Node::new(Operator::Assign)),
Token::Semicolon => Some(Node::new(Operator::Chain)),
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 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() {
result = Some(Node::new(FunctionIdentifier::new(identifier)));
result = Some(Node::new(Operator::function_identifier(identifier)));
}
}
result
},
Token::Float(float) => Some(Node::new(Const::new(Value::Float(float)))),
Token::Int(int) => Some(Node::new(Const::new(Value::Int(int)))),
Token::Boolean(boolean) => Some(Node::new(Const::new(Value::Boolean(boolean)))),
Token::String(string) => Some(Node::new(Const::new(Value::String(string)))),
}
Token::Float(float) => Some(Node::new(Operator::value(Value::Float(float)))),
Token::Int(int) => Some(Node::new(Operator::value(Value::Int(int)))),
Token::Boolean(boolean) => Some(Node::new(Operator::value(Value::Boolean(boolean)))),
Token::String(string) => Some(Node::new(Operator::value(Value::String(string)))),
};
if let Some(node) = node {

View File

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

View File

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